﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace Ezpay.UI.Controls
{
    public class AutoLayoutGrid : Grid
    {
        public int CellPadding
        {
            get { return (int)GetValue(CellPaddingProperty); }
            set { SetValue(CellPaddingProperty, value); }
        }

        public static readonly DependencyProperty CellPaddingProperty =
            DependencyProperty.Register("CellPadding", typeof(int), typeof(AutoLayoutGrid), new PropertyMetadata(0, OnCellpaddingChanged));

        
        private static void OnCellpaddingChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            var grid = dependencyObject as AutoLayoutGrid;
            grid.UpdateLayout();
        }
        public AutoLayoutGrid()
        {
            Loaded += new RoutedEventHandler(OnLoaded);
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            var childCount = VisualTreeHelper.GetChildrenCount(this);

            if(CellPadding > 0)
            {
                ApplyPadding(childCount);
            }

            ApplyGridRowColumns(childCount);
        }
        /*
         * Padding is defined as the gap between 2 adjacent controls. 
         * Since the assignments starts from top going toward right, 
         * we only need to assign top margin on controls not in first row, 
         * and assign left on controls not in first column
         */
        private void ApplyPadding(int childCount)
        {
            var padding = CellPadding;
            var childIndex = 0;
            var rowCount = RowDefinitions.Count;
            if (rowCount == 0)
                rowCount = 1;
            var columnCount = ColumnDefinitions.Count;
            if (columnCount == 0)
                columnCount = 1;
            for (int r = 0; r < rowCount; r++)
            {
                for (int c = 0; c < columnCount; c++)
                {
                    if (childIndex < childCount)
                    {
                        var top = r > 0 ? padding : 0;
                        var left = c > 0 ? padding : 0;
                        
                        var child = VisualTreeHelper.GetChild(this, childIndex);
                        child.SetValue(FrameworkElement.MarginProperty, new Thickness(left, top, 0, 0));
                        childIndex++;
                    }
                }
            }
        }

        private void ApplyGridRowColumns(int childCount)
        {
            var childIndex = 0;
            var rowCount = RowDefinitions.Count;
            if (rowCount == 0)
                rowCount = 1;
            var columnCount = ColumnDefinitions.Count;
            if (columnCount == 0)
                columnCount = 1;

            for (int r = 0; r < rowCount; r++)
            {
                
                for (int c = 0; c < columnCount; c++)
                {
                    if (childIndex < childCount)
                    {
                        var child = VisualTreeHelper.GetChild(this, childIndex);
                        child.SetValue(Grid.RowProperty, r);
                        child.SetValue(Grid.ColumnProperty, c);
                        childIndex++;
                    }
                }
            }
        }

        private void ApplyCellPadding(DependencyObject child)
        {
            var marginProperty = GetMarginProperty(child);

            if (marginProperty != null)
            {
                Binding binding = new Binding();
                binding.Source = this;
                binding.Path = new PropertyPath("CellPadding");

                BindingOperations.SetBinding(child, marginProperty, binding);
            }
        }
        private static DependencyProperty GetMarginProperty(DependencyObject dependencyObject)
        {
            foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(dependencyObject))
            {
                var dpd = DependencyPropertyDescriptor.FromProperty(propertyDescriptor);

                if (dpd != null && dpd.Name == "Margin")
                {
                    return dpd.DependencyProperty;
                }
            }

            return null;
        }
    }
}
